home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1997 January / Macworld (1997-01).dmg / Games World / Shareware Games / Arcade / Mike's Breakout / Game.u next >
Text File  |  1996-10-11  |  32KB  |  919 lines

  1. {send all comments/gripes/etc to ani@atlas.nmsu.edu}
  2. {feel free to use this code for whatever you'd like.  i'd be grateful i helped make someone's day just a bit brighter}
  3. unit Game;
  4. interface
  5.     uses
  6.         Notification, AppleTalk, PPCToolbox, Processes, EPPC, Events, AppleEvents, MTGW, TypeConst, Graphics, MTSound;
  7. {why all the toolbox stuff?  well, i made a function that (supposedly) kills other apps and the finder, and it wants this stuff}
  8.  
  9.     procedure InitOb (var WhichOb: ListGameObject; OID: integer; OInterpretID: integer; OFrame: integer; OCurrentPlace: Rect; OLastPlace: Rect; ONext: ListGameObject; OPrevious: ListGameObject; OA: integer; OB: integer; OC: integer; OD: integer; OE: integer; OVF: integer; OG: integer; OH: integer);
  10.     procedure InitGame;
  11.     procedure DisposeAll (FirstNonMovingObject, FirstMovingObject: ListGameObject);
  12.     procedure InitLevel (WhichLevel: integer; var FirstNonMovingObject: ListGameObject; var FirstMovingObject: ListGameObject);
  13.     procedure GameLoop (FirstNonMovingObject, FirstMovingObject: ListGameObject);
  14.     procedure DoCurrentKey;
  15.     procedure Interpret (WhichOb: ListGameObject);
  16.     procedure CollisionBallInterpret (var WhichOb, HitOb: ListGameObject);
  17.     procedure CollisionExplosionInterpret (var WhichOb, HitOb: ListGameObject);
  18.     procedure CollisionInterpret (var WhichOb, HitOb: ListGameObject);
  19.     procedure PaddleInterpret (WhichOb: ListGameObject);
  20.     procedure MissileInterpret (WhichOb: ListGameObject);
  21.     procedure BallInterpret (WhichOb: ListGameObject);
  22.     procedure ExplosionInterpret (WhichOb: ListGameObject);
  23.     procedure PieceInterpret (WhichOb: ListGameObject);
  24.     procedure FIREYDEATH (WhichOb: ListGameObject; XOffset, YOffset, Grow: integer);
  25.     procedure YOUSUCK (WhichOb: ListGameObject);
  26.     procedure SplitParts (WhichOb: ListGameObject);
  27.     procedure BrickEnd (WhichBrick, WhichOb: ListGameObject);
  28.     procedure MissileLaunch (var WhichOb: ListGameObject);
  29.     procedure PaddleAndBall (var FirstObject: ListGameObject);
  30.     function Collision (FirstRect: Rect; SecondRect: Rect): Rect;
  31.     function NormalCollision (var CurrOb: ListGameObject): Boolean;
  32.     procedure BrickRow (var StartOb: ListGameObject; XStart: integer; YStart: integer; NumBricks: integer);
  33.     procedure InitNonMovingGrid;
  34.     procedure RemoveFromNonMovingGrid (CurrOb: ListGameObject);
  35.     procedure AddToNonMovingGrid (CurrOb: ListGameObject);
  36.     procedure UpdateNonMovingGrid (CurrOb: ListGameObject);
  37.     procedure KillEveryBody;
  38.  
  39.     var    {explained when they are used}
  40.         OtherBool, DontSuck, PaddleDeath, BallDeath, ShiftKeyIsDown, GotEvent, Done: Boolean;
  41.         CurrentEvent: EventRecord;
  42.         CurrentKey: char;
  43.         Temp: integer;
  44.         TempOb: ListGameObject;
  45.         FirstPlace, TempPlace: Rect;
  46.         Topscore: file of longint;
  47.  
  48. implementation
  49.  
  50.     procedure KillEveryBody;    {ok i haven't looked over this function 100%, as it is only a conversion}
  51. {of a C program i found somewhere on apple's site to pascal, and I may have converted improperly.  the}
  52. {function SHOULD kill all other processes, but most of the time when i try it, it will do that, then crash}
  53. {my machine sometime later.  have a look-see yourself}
  54.         var
  55.             finderPSN, myProc, processSN: ProcessSerialNumber;
  56.             inforec: ProcessInfoRec;
  57.             processName: Str31;
  58.             procSpec: FSSpec;
  59.             fredErr, myErr, otherError: OsErr;
  60.             replyEvent, theEvent: AppleEvent;
  61.             theAddress: AEDesc;
  62.             ourFlag, notFinder: Boolean;
  63.             finderFound: Boolean;
  64.     begin
  65.         fredErr := GetCurrentProcess(myProc);
  66.         processSN.lowLongOfPSN := kNoProcess;
  67.         myerr := noErr;
  68.         finderFound := FALSE;
  69.         processSN.highLongOfPSN := kNoProcess;
  70.         finderPSN.lowLongOfPSN := 0;
  71.         finderPSN.highLongOfPSN := 0;
  72.  
  73.         repeat
  74.             myErr := GetNextProcess(processSN);
  75.             notFinder := true;
  76.             fredErr := SameProcess(myProc, processSN, ourFlag);
  77.             infoRec.processInfoLength := sizeof(ProcessInfoRec);
  78.             infoRec.processName := @processName;
  79.             infoRec.processAppSpec := @procSpec;
  80.             fredErr := GetProcessInformation(processSN, infoRec);
  81.             if ((not ourFlag) and (not finderFound)) then
  82.                 begin
  83.                     if (infoRec.processSignature = 'MACS') and (infoRec.processType = longint('FNDR')) then
  84.                         begin
  85.                             finderPSN := processSN;
  86.                             notFinder := false;
  87.                             finderFound := true;
  88.                         end
  89.                     else
  90.                         notFinder := true;
  91.                 end;
  92.             if ((myErr = noerr) and ((not ourFlag) and (notFinder))) then
  93.                 otherError := AECreateDesc(typeProcessSerialNumber, Ptr(@processSN), sizeof(processSN), theAddress);
  94.             if (otherError = noerr) then
  95.                 otherError := AECreateAppleEvent(kCoreEventClass, kAEQuitApplication, theAddress, kAutoGenerateReturnID, kAnyTransactionID, theEvent);
  96.             if (otherError = noerr) then
  97.                 fredErr := AEDisposeDesc(theAddress);
  98.             if (otherError = noerr) then
  99.                 fredErr := AESend(theEvent, replyEvent, kAENoReply + kAEAlwaysInteract + kAECanSwitchLayer, kAENormalPriority, kAEDefaultTimeout, nil, nil);
  100.             fredErr := AEDisposeDesc(theEvent);
  101.         until (myErr <> noerr);
  102.  
  103.         if ((finderPSN.lowLongOfPSN <> 0) or (finderPSN.highLongOfPSN <> 0)) then
  104.             otherError := AECreateDesc(typeProcessSerialNumber, Ptr(@finderPSN), sizeof(processSN), theAddress);
  105.         if (otherError = noerr) then
  106.             otherError := AECreateAppleEvent(kCoreEventClass, kAEQuitApplication, theAddress, kAutoGenerateReturnID, kAnyTransactionID, theEvent);
  107.         if (otherError = noerr) then
  108.             fredErr := AEDisposeDesc(theAddress);
  109.         if (otherError = noerr) then
  110.             fredErr := AESend(theEvent, replyEvent, kAENoReply + kAEAlwaysInteract + kAECanSwitchLayer, kAENormalPriority, kAEDefaultTimeout, nil, nil);
  111.         fredErr := AEDisposeDesc(theEvent);
  112.     end;        {fun stuff...}
  113.  
  114.     procedure CollisionBallInterpret;
  115.     begin
  116.         case HitOb^.InterpretID of
  117.             BRICK: 
  118.                 begin
  119. {BrickEnd(HitOb, WhichOb);}
  120. {uncomment previous line to have brick do a shrinking animation (and slow your machine, ugh)}
  121.                     with WhichOb^ do
  122.                         begin
  123.                             F := C;
  124.                             if C > 0 then
  125.                                 C := C - 1;
  126.                         end;
  127.                     HitOb^.DoDispose := TRUE;
  128.                     PlaySound(129);
  129.                 end;
  130.             BRICKII: 
  131.                 begin
  132.                     if WhichOb^.C <> 0 then
  133.                         begin
  134.                             HitOb^.DoDispose := TRUE;
  135.                             PlaySound(129);
  136.                         end
  137.                     else
  138.                         PlaySound(132);
  139.                     WhichOb^.C := 0;
  140.                 end;
  141.         end;
  142.     end;        {this function checks what to do when the ball collides with a certain object}
  143.  
  144.     procedure CollisionExplosionInterpret;
  145.     begin
  146.         case HitOb^.ID of
  147.             BRICK: 
  148.                 begin
  149. {BrickEnd(HitOb, WhichOb);}
  150.                     HitOb^.DoDispose := TRUE;
  151.                 end;
  152.         end;
  153.     end;        {this checks what to do when an explosion hits an object}
  154.  
  155.     procedure CollisionInterpret;
  156.     begin
  157.         case WhichOb^.ID of
  158.             BALL: 
  159.                 begin
  160.                     CollisionBallInterpret(WhichOb, HitOb);
  161.                 end;
  162.             EXPLOSION: 
  163.                 CollisionExplosionInterpret(WhichOb, HitOb);
  164.             otherwise
  165.                 ;
  166.         end;
  167.     end;        {this goes to the correct interpretation for collisions, depending on the object;}
  168.             {function pointers would probably be better}
  169.  
  170.     function NormalCollision;
  171.         var
  172.             WhereX, WhereY, k: integer;
  173.             ReturnValue: Boolean;
  174.     begin
  175.         ReturnValue := FALSE;
  176.         for WhereX := (CurrOb^.CurrentPlace.left) div BLOCKSIZE to (CurrOb^.CurrentPlace.right) div BLOCKSIZE do
  177.             for WhereY := (CurrOb^.CurrentPlace.top) div BLOCKSIZE to (CurrOb^.CurrentPlace.bottom) div BLOCKSIZE do
  178.                 if (WhereX >= 0) and (WhereY >= 0) and (WhereX < MAXGRIDX) and (WhereY < MAXGRIDY) then
  179.                     for k := 1 to 5 do        {check each grid object in the part of the grid that the current object covers}
  180.                         begin
  181.                             if NonMovingGrid[WhereX, WhereY, k] <> nil then        {we got something?  if so call collisioninterpret}
  182.                                 begin
  183.                                     if SectRect(NonMovingGrid[WhereX, WhereY, k]^.CurrentPlace, CurrOb^.CurrentPlace, TempPlace) then
  184.                                         begin
  185.                                             CollisionInterpret(CurrOb, NonMovingGrid[WhereX, WhereY, k]);
  186.                                             ReturnValue := TRUE;
  187.                                         end;
  188.                                 end;
  189.                         end;
  190.         NormalCollision := ReturnValue;
  191.     end;        {grid type of collision}
  192.  
  193.     function Collision;
  194.         var
  195.             ReturnVariable: Rect;
  196.     begin
  197.         if not SectRect(FirstRect, SecondRect, ReturnVariable) then
  198.             ReturnVariable.top := -1
  199.         else
  200.             PlaySound(129);
  201.         Collision := ReturnVariable;
  202.     end;        {check if too objects collided (and play fun sound) }
  203.  
  204.     procedure InitOb;        {each object property is described here!}
  205.     begin
  206.         with WhichOb^ do
  207.             begin
  208.                 ID := OID;                                {This is the drawing ID (very much wants to be a function pointer)}
  209.                 InterpretId := OInterpretID;            {This is the interpret, or heart_beat id, the func called every iteration ("")}
  210.                 Frame := OFrame;                    {This is the frame counter}
  211.                 CurrentPlace := OCurrentPlace;    {A rect for the current location}
  212.                 LastPlace := OLastPlace;            {A rect for the last location}
  213.                 Next := ONext;                        {the next object in the linked list}
  214.                 Previous := OPrevious;                {the previous object in the linked list}
  215.                 A := OA;                                {A-D misc values}
  216.                 B := OB;
  217.                 C := OC;
  218.                 D := OD;
  219.                 DoDispose := FALSE;                    {this important variable decides if the object is to be removed from memory}
  220.                                                 {at the end of a turn of the main loop}
  221.             end;
  222.     end;
  223. {this is very simply a macro to put all of an object's properties in one line}
  224.  
  225.     procedure YOUSUCK;
  226.         var
  227.             WhichRect: Rect;
  228.             CurrOb: ListGameObject;
  229.     begin
  230.         CurrOb := WhichOb;
  231.         while CurrOb^.previous <> nil do
  232.             CurrOb := CurrOb^.previous;
  233.         new(CurrOb^.previous);
  234.         PlaySound(134);
  235.         with WhichOb^ do
  236.             CoordAndSize(WhichRect, WhichOb^.CurrentPlace.left, WhichOb^.CurrentPlace.top - 20, CIcons[900]^^.IconPmap.Bounds.right, CIcons[900]^^.IconPmap.Bounds.bottom);
  237.         InitOb(CurrOb^.previous, PADDLEEXP, PADDLEEXP, 899, WhichRect, WhichRect, CurrOb, nil, 0, 0, 0, 0, 0, 0, 0, 0);
  238.     end;        {game over function, creates and explosion at the very beginning of the linked list}
  239.             {we also have michael to thank for the 'colourful' function name}
  240.  
  241.     procedure SplitParts;
  242.         var
  243.             WhichRect: Rect;
  244.             StartOb, CurrOb: ListGameObject;
  245.     begin
  246.         StartOb := WhichOb;
  247.         CurrOb := WhichOb^.Next;
  248.         WhichOb^.Next := nil;
  249.         new(WhichOb^.Next);        {create a new object AFTER the explosion (or the caller of this function)}
  250.         with WhichOb^.Next^ do
  251.             CoordAndSize(WhichRect, WhichOb^.CurrentPlace.left, WhichOb^.CurrentPlace.top + 10, CIcons[1000]^^.IconPmap.Bounds.right, CIcons[1000]^^.IconPmap.Bounds.bottom);
  252.         InitOb(WhichOb^.Next, PADDLEPIECE, PADDLEPIECE, 1000, WhichRect, WhichRect, CurrOb, WhichOb, -15, -2, 0, 0, 0, 0, 0, 0);
  253.         CurrOb^.Previous := WhichOb^.Next;
  254.         WhichOb := CurrOb;
  255.         CurrOb := WhichOb^.Next;
  256.         WhichOb^.Next := nil;
  257.         new(WhichOb^.Next);        {create another piece after the previous piece}
  258.         with WhichOb^.Next^ do
  259.             with WhichOb^ do
  260.                 CoordAndSize(WhichRect, StartOb^.CurrentPlace.left + 23, StartOb^.CurrentPlace.top + 10, CIcons[1050]^^.IconPmap.Bounds.right, CIcons[1050]^^.IconPmap.Bounds.bottom);
  261.         InitOb(WhichOb^.Next, PADDLEPIECE, PADDLEPIECE, 1050, WhichRect, WhichRect, CurrOb, WhichOb, 15, -2, 0, 0, 0, 0, 0, 0);
  262.         if CurrOb <> nil then
  263.             CurrOb^.Previous := WhichOb^.Next;
  264.     end;        {this function creates two ends of the paddle}
  265.  
  266.     procedure FIREYDEATH;
  267.         var
  268.             WhichRect: Rect;
  269.             CurrOb: ListGameObject;
  270.     begin
  271.         CurrOb := WhichOb;
  272.         while CurrOb^.previous <> nil do
  273.             CurrOb := CurrOb^.previous;
  274.         PlaySound(133);
  275.         new(CurrOb^.previous);    {create an explosion at the very beginning of the list}
  276.         with WhichOb^ do
  277.             CoordAndSize(WhichRect, XOffset + ((WhichOb^.CurrentPlace.left + WhichOb^.CurrentPlace.right) div 2) - ((CIcons[400]^^.IconPmap.Bounds.right) div 2) - 10, YOffset + ((WhichOb^.CurrentPlace.top + WhichOb^.CurrentPlace.bottom) div 2) - ((CIcons[400]^^.IconPmap.Bounds.bottom) div 2), CIcons[400]^^.IconPmap.Bounds.right, CIcons[400]^^.IconPmap.Bounds.bottom);
  278. {^ this long call here just centers the explosion where the thing blew up}
  279.         InsetRect(WhichRect, -Grow, -Grow);
  280.         InitOb(CurrOb^.previous, EXPLOSION, EXPLOSION, 399, WhichRect, WhichRect, CurrOb, nil, 0, 0, 0, 0, 0, 0, 0, 0);
  281.         with CurrOb^.previous^.CurrentPlace do
  282.             begin
  283.                 right := right + 20;
  284.                 bottom := bottom + 10;
  285.             end;        {make it a bit bigger for the flames to fit}
  286.         if NormalCollision(CurrOb^.previous) then
  287.             ;    {check if we hit anything with the explosion}
  288.         with CurrOb^.previous^ do
  289.             begin
  290.                 LastPlace := CurrentPlace;
  291.                 CurrentPlace := WhichRect;
  292.                 InsetRect(LastPlace, -Grow, -Grow);
  293.             end;
  294.     end;        {another 'mike' function name, this creates an all purpose explosion}
  295.  
  296.     procedure BrickEnd;
  297.         var
  298.             CurrOb: ListGameObject;
  299.     begin
  300.         CurrOb := WhichOb;
  301.         while CurrOb^.previous <> nil do
  302.             CurrOb := CurrOb^.previous;
  303.         new(CurrOb^.previous);            {very beginning of list again}
  304.         InitOb(CurrOb^.previous, DEADBRICK, DEADBRICK, 1100, WhichBrick^.CurrentPlace, WhichBrick^.CurrentPlace, CurrOb, nil, 0, 0, 0, 0, 0, 0, 0, 0);
  305.     end;        {this creates a new object for a shrinking brick}
  306.  
  307.     procedure MissileLaunch;
  308.         var
  309.             WhichRect: Rect;
  310.             NewOb, CurrOb: ListGameObject;
  311.     begin
  312.         CurrOb := WhichOb^.previous;
  313.         WhichOb^.previous := nil;
  314.         PlaySound(131);
  315.         new(WhichOb^.previous);        {create it before the current object}
  316.         NewOb := WhichOb^.previous;
  317.         if CurrOb <> nil then
  318.             CurrOb^.next := NewOb;
  319.         CoordAndSize(WhichRect, WhichOb^.CurrentPlace.left + 26, WhichOb^.CurrentPlace.top - 7, CIcons[600]^^.IconPmap.Bounds.right, CIcons[600]^^.IconPmap.Bounds.bottom);
  320.         InitOb(NewOb, MISSILE, MISSILE, 350, WhichRect, WhichRect, WhichOb, CurrOb, 0, 0, 0, 0, 0, 0, 0, 0);
  321.     end;        {just create a missle}
  322.  
  323.     procedure ExplosionInterpret;
  324.     begin
  325.         with WhichOb^ do
  326.             begin
  327.             end;
  328.     end;        {explosion doesn't do anything but look cool after it's initial creation}
  329.  
  330.     procedure BallInterpret;
  331.     begin
  332.         TempBool := FALSE;
  333.         OtherBool := FALSE;        {these are used for collisions}
  334.         with WhichOb^ do
  335.             begin
  336.                 F := 0;
  337.                 FirstPlace := CurrentPlace;
  338.                 if A > 0 then        {going right?}
  339.                     begin
  340.                         OffsetRect(CurrentPlace, A, 0);
  341.                         D := 0;        {move rect right, init this temp var}
  342.                         if (WhichOb^.previous^.ID = PADDLE) then
  343.                             begin
  344.                                 TempPlace := Collision(CurrentPlace, WhichOb^.previous^.CurrentPlace);
  345.                                 D := integer(TempPlace.top <> -1);
  346.                                 if (D <> 0) then
  347.                                     C := 0;    {if we collided with something other then the top, unset the velocity going up or down}
  348.                             end;
  349.                         OtherBool := (CurrentPlace.right > RIGHTBOUNDRY);
  350.                         if OtherBool or (D <> 0) or NormalCollision(WhichOb) then { or collision }
  351.                             begin
  352.                                 if F = 0 then
  353.                                     A := -1 * A;        {if there was a collision then go the other way}
  354.                                 CurrentPlace := FirstPlace;
  355.                             end;
  356.                     end
  357.                 else if A < 0 then        {going left looks like going right, so look at it for details}
  358.                     begin
  359.                         OffsetRect(CurrentPlace, A, 0);
  360.                         D := 0;
  361.                         if (WhichOb^.previous^.ID = PADDLE) then
  362.                             begin
  363.                                 TempPlace := Collision(CurrentPlace, WhichOb^.previous^.CurrentPlace);
  364.                                 D := integer(TempPlace.top <> -1);
  365.                                 if (D <> 0) then
  366.                                     C := 0;
  367.                             end;
  368.                         OtherBool := (CurrentPlace.left < LEFTBOUNDRY);
  369.                         if OtherBool or (D <> 0) or NormalCollision(WhichOb) then
  370.                             begin
  371.                                 if F = 0 then
  372.                                     A := -1 * A;
  373.                                 CurrentPlace := FirstPlace;
  374.                             end;
  375.                     end;
  376.                 F := 0;
  377.                 if OtherBool then
  378.                     PlaySound(129);
  379.                 if B = 1 then        {going down?}
  380.                     begin
  381.                         OffsetRect(CurrentPlace, 0, 6 * ((C + 4) div 4));    {move depending on the velocity, C}
  382.                         D := 0;
  383.                         if (WhichOb^.previous^.ID = PADDLE) then
  384.                             begin
  385.                                 TempPlace := Collision(CurrentPlace, WhichOb^.previous^.CurrentPlace);
  386.                                 if TempPlace.top <> -1 then
  387.                                     D := (TempPlace.right + TempPlace.left) div 2 - WhichOb^.previous^.CurrentPlace.left
  388.                                 else
  389.                                     D := 0;
  390.                             end;        {check for collision with paddle}
  391.                         TempBool := (CurrentPlace.bottom > BOTTOMBOUNDRY);        {you lost your ball!}
  392.                         if TempBool or (D <> 0) or NormalCollision(WhichOb) then {collision with paddle or otherwise}
  393.                             begin
  394.                                 if F = 0 then
  395.                                     B := -1 * B;
  396.                                 if D <> 0 then
  397.                                     begin
  398.                                         A := ((D - 30) div 7) * 3;
  399.                                         C := 0;
  400.                                     end;
  401.                                 CurrentPlace := FirstPlace;
  402.                             end;
  403.                     end
  404.                 else        {going up here, very much like going down, except you don't die if you hit the top}
  405.                     begin
  406.                         OffsetRect(CurrentPlace, 0, -6 * ((C + 4) div 4));
  407.                         D := 0;
  408.                         if (WhichOb^.previous^.ID = PADDLE) then
  409.                             begin
  410.                                 TempPlace := Collision(CurrentPlace, WhichOb^.previous^.CurrentPlace);
  411.                                 if TempPlace.top <> -1 then
  412.                                     D := (TempPlace.right + TempPlace.left) div 2 - WhichOb^.previous^.CurrentPlace.left
  413.                                 else
  414.                                     D := 0;
  415.                             end;
  416.                         OtherBool := (CurrentPlace.top < TOPBOUNDRY);
  417.                         if OtherBool or (D <> 0) or NormalCollision(WhichOb) then
  418.                             begin
  419.                                 if F = 0 then
  420.                                     B := -1 * B;
  421.                                 if D <> 0 then
  422.                                     begin
  423.                                         A := ((D - 30) div 7) * 3;
  424.                                         C := 0;
  425.                                     end;
  426.                                 CurrentPlace := FirstPlace;
  427.                             end;
  428.                     end;
  429.                 if TempBool or BallDeath then    {if you lose}
  430.                     begin
  431.                         DoDispose := TRUE;
  432.                         FIREYDEATH(WhichOb, 0, 0, 20);
  433.                         PaddleDeath := True;
  434.                         DeathCountdown := 1;    {one of the 2 is lost (other two are paddle pieces)}
  435.                     end;
  436.                 if OtherBool then
  437.                     PlaySound(129);    {hit a side}
  438.             end;
  439.     end;
  440.  
  441.     procedure MissileInterpret;
  442.     begin
  443.         with WhichOb^ do
  444.             begin
  445.                 if (A > -14) then
  446.                     A := A - 1;        {missile goes faster every round}
  447.                 OffsetRect(CurrentPlace, 0, A);
  448.                 if (CurrentPlace.top < 0) or NormalCollision(WhichOb) then
  449.                     begin
  450.                         DoDispose := TRUE;
  451.                         FIREYDEATH(WhichOb, 0, 0, 0);        {make an explosion where it hit}
  452. {Collide with ceil}
  453.                     end;
  454.             end;
  455.     end;
  456.  
  457.     procedure PaddleInterpret;
  458.     begin
  459.         with WhichOb^ do
  460.             begin
  461.                 A := 0;
  462.                 if (E = 0) and (CurrentKey = ' ') then        {pressed for trampoline?}
  463.                     begin
  464.                         E := 15;
  465.                     end;
  466.                 if C <> 0 then                                {missile launching var}
  467.                     begin
  468.                         if C = 1 then
  469.                             begin
  470.                                 frame := frame + 1;                    {open the doors}
  471.                                 if frame = 203 then
  472.                                     MissileLaunch(WhichOb);            {all the way open?  do the missile!}
  473.                             end
  474.                         else
  475.                             frame := frame - 1;                    {close the doors}
  476.                         if frame = 206 then
  477.                             C := 2;
  478.                         if frame = 200 then
  479.                             C := 0;
  480.                     end
  481.                 else
  482.                     begin
  483.                         case CurrentKey of                        {pretty easy stuff, if you pressed right or left go that way}
  484.                             RIGHTKEY: 
  485.                                 begin
  486.                                     A := FLAMELEFT;
  487.                                     if ShiftKeyIsDown then
  488.                                         OffsetRect(CurrentPlace, PADDLESPEED * 3, 0)
  489.                                     else
  490.                                         OffsetRect(CurrentPlace, PADDLESPEED, 0);
  491.                                     Temp := CurrentPlace.right - RIGHTBOUNDRY;
  492.                                     if Temp > 0 then
  493.                                         begin
  494.                                             CurrentPlace.right := CurrentPlace.right - Temp;
  495.                                             CurrentPlace.left := CurrentPlace.left - Temp;
  496.                                         end;
  497.                                 end;
  498.                             LEFTKEY: 
  499.                                 begin
  500.                                     A := FLAMERIGHT;
  501.                                     if ShiftKeyIsDown then
  502.                                         OffsetRect(CurrentPlace, -PADDLESPEED * 3, 0)
  503.                                     else
  504.                                         OffsetRect(CurrentPlace, -PADDLESPEED, 0);
  505.                                     Temp := LEFTBOUNDRY - CurrentPlace.left;
  506.                                     if Temp > 0 then
  507.                                         begin
  508.                                             CurrentPlace.right := CurrentPlace.right + Temp;
  509.                                             CurrentPlace.left := CurrentPlace.left + Temp;
  510.                                         end;
  511.                                 end;
  512.                             LAUNCHKEY:     {begin missile launching}
  513.                                 begin
  514.                                     if Missiles > 0 then
  515.                                         begin
  516.                                             C := 1;
  517.                                             Missiles := Missiles - 1;
  518.                                         end
  519.                                     else
  520.                                         ;
  521.                                 end;
  522.                             otherwise
  523.                                 ;
  524.                         end;
  525.                     end;
  526.                 if (E <> 0) then        {play with trampoline?}
  527.                     begin
  528.                         if E > 10 then
  529.                             begin
  530.                                 CoordAndSize(ExtraRectA, CurrentPlace.left + 11, CurrentPlace.top - 8, CIcons[650]^^.IconPmap.Bounds.right, CIcons[650]^^.IconPmap.Bounds.bottom);
  531.                                 TempOb := WhichOb^.next;
  532.                                 if TempOb <> nil then
  533.                                     begin
  534.                                         if TempOb^.ID = BALL then        {did we smack that ball?}
  535.                                             begin
  536.                                                 TempPlace := Collision(ExtraRectA, TempOb^.CurrentPlace);
  537.                                                 if TempPlace.top <> -1 then
  538.                                                     begin
  539.                                                         PlaySound(130);
  540.                                                         TempOb^.B := -1;
  541.                                                         if (TempOb^.C < 8) then
  542.                                                             TempOb^.C := TempOb^.C + 4;        {launch ball with tremendous speed!}
  543.                                                     end;
  544.                                             end;
  545.                                     end;
  546.                             end
  547.                         else
  548.                             CoordAndSize(ExtraRectA, CurrentPlace.left + 11, CurrentPlace.top + (2 - E), CIcons[650]^^.IconPmap.Bounds.right, CIcons[650]^^.IconPmap.Bounds.bottom);
  549.                     end;
  550.                 if PaddleDeath then
  551.                     begin
  552.                         DoDispose := TRUE;
  553.                         PaddleDeath := FALSE;
  554.                         YOUSUCK(WhichOb);        {get ready to lose a life}
  555.                     end;
  556.             end;
  557.     end;
  558.  
  559.     procedure PieceInterpret;
  560.     begin
  561.         with WhichOb^ do
  562.             begin
  563.                 OffSetRect(CurrentPlace, A, B);
  564.                 B := B + 1;
  565.                 C := C + 1;
  566.                 if C = 8 then
  567.                     C := 0;
  568.             end;
  569.     end;        {just animate it, use C for frame counter, and play with gravity using B}
  570.  
  571.     procedure Interpret;
  572.     begin
  573.         if WhichOb^.InterpretID <> 0 then
  574.             begin
  575.                 case WhichOb^.InterpretID of
  576.                     PADDLE: 
  577.                         PaddleInterpret(WhichOb);
  578.                     MISSILE: 
  579.                         MissileInterpret(WhichOb);
  580.                     BALL: 
  581.                         BallInterpret(WhichOb);
  582.                     EXPLOSION: 
  583.                         ExplosionInterpret(WhichOb);
  584.                     PADDLEPIECE: 
  585.                         PieceInterpret(WhichOb);
  586.                     PADDLEEXP: 
  587.                         if WhichOb^.frame = 904 then
  588.                             SplitParts(WhichOb);
  589.                     otherwise
  590.                         ;
  591.                 end;
  592.             end;
  593.     end;        {instead of function pointer, pick the one that coresponds to the interpreting id}
  594.  
  595.     procedure DoCurrentKey;
  596.     begin
  597.         GotEvent := GetOSEvent(everyEvent, CurrentEvent);
  598.         CurrentKey := char(0);
  599.         ShiftKeyIsDown := FALSE;
  600.         if GotEvent then
  601.             begin
  602.                 if (CurrentEvent.What = keyDown) or (CurrentEvent.What = autoKey) then
  603.                     CurrentKey := char(BitAnd(CurrentEvent.Message, charCodeMask));
  604.                 if BitAnd(CurrentEvent.Modifiers, shiftKey) <> 0 then
  605.                     ShiftKeyIsDown := TRUE;
  606.             end;
  607.         if CurrentKey = QUITKEY then
  608.             Done := TRUE;
  609.     end;        {basic toolbox fun, get the next event that happened and throw it in}
  610.  
  611.     procedure GameLoop;    {woo this is the main loop}
  612.         var
  613.             j, i: integer;
  614.             CurrentKey: char;
  615.             NextLevel: Boolean;
  616.             NextObject, PreviousObject, CurrObject: ListGameObject;
  617.     begin
  618.         Done := FALSE;
  619.         while not Done do
  620.             begin
  621.                 NextLevel := FALSE;
  622.                 DisposeAll(FirstNonMovingObject, FirstMovingObject);
  623.                 InitLevel(1, FirstNonMovingObject, FirstMovingObject);        {init everything, get rid of stuff every level}
  624.                 while not Done and not NextLevel do
  625.                     begin
  626.                         begin
  627.                             DoCurrentKey;
  628.                             if CoolnessCounter > 0 then
  629.                                 CoolnessCounter := CoolnessCounter - 1;                {this is a really bad way to give sounds priority(more later)}
  630.                             while FirstNonMovingObject^.previous <> nil do
  631.                                 FirstNonMovingObject := FirstNonMovingObject^.previous;
  632.                             while FirstMovingObject^.previous <> nil do
  633.                                 FirstMovingObject := FirstMovingObject^.previous;    {go to beginning of list on both lists}
  634.                             if DeathCountdown = 3 then
  635.                                 begin
  636.                                     Lives := Lives - 1;
  637.                                     if Lives < 1 then
  638.                                         begin
  639.                                             Done := TRUE;
  640.                                             rewrite(TopScore, 'HighScore');
  641.                                             TopScore^ := top;
  642.                                             put(TopScore);
  643.                                             close(TopScore);        {you lose a life, high score is written (wow, something mike actually did) }
  644.                                         end
  645.                                     else
  646.                                         PaddleAndBall(FirstMovingObject);        {this creates the paddle and the ball}
  647.                                     DeathCountdown := 0;
  648.                                 end;
  649.                             CurrObject := FirstMovingObject;
  650.                             FixErasure(FirstMovingObject);                {erase everything}
  651.                             while CurrObject <> nil do
  652.                                 begin
  653.                                     Interpret(CurrObject);
  654.                                     Draw(CurrObject);                            {for each object, draw and interpret}
  655.                                     if CurrObject^.DoDispose then
  656.                                         begin
  657.                                             NextObject := CurrObject^.next;
  658.                                             PreviousObject := CurrObject^.previous;
  659.                                             if PreviousObject <> nil then
  660.                                                 PreviousObject^.next := NextObject;
  661.                                             if NextObject <> nil then
  662.                                                 NextObject^.Previous := PreviousObject;
  663.                                             if CurrObject = FirstMovingObject then
  664.                                                 FirstMovingObject := NextObject;
  665.                                             dispose(CurrObject);
  666.                                             CurrObject := NextObject;        {this just gets rid of one object!  complicated work, sort of, as}
  667.                                         end                                    {several checks are done, so it doesn't go before first, after last etc}
  668.                                     else
  669.                                         CurrObject := CurrObject^.Next;
  670.                                 end;
  671.                             DrawGridSquares;
  672.                             CurrObject := FirstNonMovingObject;
  673.                             i := 0;
  674.                             while CurrObject <> nil do    {this loop is for grid, and gives you points when needed}
  675.                                 begin
  676.                                     begin
  677.                                         i := i + 1;
  678.                                         if CurrObject^.DoDispose then
  679.                                             begin
  680.                                                 for j := 1 to CurrObject^.A do
  681.                                                     begin
  682.                                                         score := score + 1;
  683.                                                         if (score mod 100) = 0 then
  684.                                                             lives := lives + 1;
  685.                                                         if (score mod 10) = 0 then
  686.                                                             Missiles := Missiles + 1;        {every 100 a life, every 10 a missile (sounds fair to me)}
  687.                                                     end;
  688.                                                 if (score > top) then
  689.                                                     begin
  690.                                                         top := score;
  691.                                                         if not DontSuck then
  692.                                                             begin
  693.                                                                 DontSuck := TRUE;
  694.                                                                 PlaySound(135);
  695.                                                                 CoolnessCounter := 35;        {this plays the high score sound, then gives a counter for priority}
  696.                                                             end;
  697.                                                     end;
  698.                                                 AddCopyRect(CurrObject^.CurrentPlace);
  699.                                                 EraseRect(CurrObject^.CurrentPlace);
  700.                                                 RemoveFromNonMovingGrid(CurrObject);
  701.                                                 NextObject := CurrObject^.next;
  702.                                                 PreviousObject := CurrObject^.previous;
  703.                                                 if PreviousObject <> nil then
  704.                                                     PreviousObject^.next := NextObject;
  705.                                                 if NextObject <> nil then
  706.                                                     NextObject^.Previous := PreviousObject;
  707.                                                 if CurrObject = FirstMovingObject then
  708.                                                     FirstMovingObject := NextObject;
  709.                                                 dispose(CurrObject);
  710.                                                 CurrObject := NextObject;                {this just gets rid of it, as well as removing it from grid}
  711.                                             end
  712.                                         else
  713.                                             CurrObject := CurrObject^.Next;
  714.                                     end
  715.                                 end;
  716.                             if (i = 1) and (DeathCountdown = 0) then    {i is the num of grid objects; which are bricks.. the one left is}
  717.                                                                 {a dummy object to keep things happy}
  718.                                 begin
  719.                                     PlaySound(136);
  720.                                     NextLevel := TRUE;                        {happy day, you advanced to the next level}
  721.                                 end;
  722.                             DrawCopyRects;
  723.                         end;
  724.                     end;
  725.             end;
  726.         RestoreGraphics;
  727.     end;
  728.  
  729.     procedure DisposeAll;
  730.         var
  731.             DisposeObject, CurrObject: ListGameObject;
  732.     begin
  733.         CurrObject := FirstMovingObject;
  734.         while CurrObject <> nil do
  735.             begin
  736.                 DisposeObject := CurrObject^.Next;
  737.                 dispose(CurrObject);
  738.                 CurrObject := DisposeObject;
  739.             end;
  740.         CurrObject := FirstNonMovingObject;
  741.         while CurrObject <> nil do
  742.             begin
  743.                 DisposeObject := CurrObject;
  744.                 CurrObject := CurrObject^.Next;
  745.                 dispose(DisposeObject);
  746.             end;
  747.     end;        {very simply, get rid of all objects in both lists}
  748.  
  749.     procedure PaddleAndBall;
  750.         var
  751.             CurrObject: ListGameObject;
  752.             CurrentRect: Rect;
  753.     begin
  754.         CurrObject := FirstObject;
  755.         new(FirstObject^.next);
  756.         CurrObject := FirstObject^.next;
  757.         CurrentRect := CIcons[200]^^.IconPmap.Bounds;
  758.         OffsetRect(CurrentRect, 225, 275);
  759.         InitOb(CurrObject, PADDLE, PADDLE, 200, CurrentRect, CurrentRect, nil, FirstObject, 0, 0, 0, 0, 0, 0, 0, 0);
  760.         new(CurrObject^.next);
  761.         CurrentRect := CIcons[300]^^.IconPmap.Bounds;
  762.         OffsetRect(CurrentRect, 255, 250);
  763.         InitOb(CurrObject^.next, BALL, BALL, 300, CurrentRect, CurrentRect, nil, CurrObject, (random mod 5), 1, 1, 0, 0, 0, 0, 0);
  764.     end;        {create, and init, both paddle and ball}
  765.  
  766.     procedure UpdateNonMovingGrid;
  767.         var
  768.             WhereX, WhereY: integer;
  769.     begin
  770.         for WhereX := (CurrOb^.CurrentPlace.left) div BLOCKSIZE to (CurrOb^.CurrentPlace.right) div BLOCKSIZE do
  771.             for WhereY := (CurrOb^.CurrentPlace.top) div BLOCKSIZE to (CurrOb^.CurrentPlace.bottom) div BLOCKSIZE do
  772.                 begin
  773.                     CurrentNonMoving := CurrentNonMoving + 1;
  774.                     with NonMovingList[CurrentNonMoving] do
  775.                         begin
  776.                             H := WhereX;
  777.                             V := WhereY;
  778.                         end;
  779.                 end;
  780.     end;        {does as addtononmovinggrid except doesn't draw}
  781.  
  782.     procedure RemoveFromNonMovingGrid;
  783.         var
  784.             i, WhereX, WhereY: integer;
  785.     begin
  786.         for WhereX := (CurrOb^.CurrentPlace.left) div BLOCKSIZE to (CurrOb^.CurrentPlace.right) div BLOCKSIZE do
  787.             for WhereY := (CurrOb^.CurrentPlace.top) div BLOCKSIZE to (CurrOb^.CurrentPlace.bottom) div BLOCKSIZE do
  788.                 for i := 1 to 5 do
  789.                     if NonMovingGrid[WhereX, WhereY, i] = CurrOb then
  790.                         NonMovingGrid[WhereX, WhereY, i] := nil;
  791.     end;        {get rid of it pretty much the same way it was created, from each of its blocks}
  792.  
  793.     procedure AddToNonMovingGrid;
  794.         var
  795.             a, b, c, d, i, WhereX, WhereY: integer;
  796.     begin
  797.         for WhereX := ((CurrOb^.CurrentPlace.left) div BLOCKSIZE) to ((CurrOb^.CurrentPlace.right) div BLOCKSIZE) do
  798.             for WhereY := ((CurrOb^.CurrentPlace.top) div BLOCKSIZE) to ((CurrOb^.CurrentPlace.bottom) div BLOCKSIZE) do
  799.                 begin
  800.                     i := 1;
  801.                     while NonMovingGrid[WhereX, WhereY, i] <> nil do
  802.                         i := i + 1;
  803.                     NonMovingGrid[WhereX, WhereY, i] := CurrOb;
  804.                     if FALSE then
  805.                         begin
  806.                             CurrentNonMoving := CurrentNonMoving + 1;
  807.                             with NonMovingList[CurrentNonMoving] do
  808.                                 begin
  809.                                     H := WhereX;
  810.                                     V := WhereY;
  811.                                 end;
  812.                         end;        {this USED to be a different way of doing it... i changed it, of course}
  813.                     Draw(CurrOb);
  814.                 end;
  815.     end;        {stick an object in the grid, which includes setting each grid block it's in}
  816.  
  817.     procedure BrickRow;
  818.         var
  819.             CurrLeft, BrickWidth, BrickHeight, i: integer;
  820.             PrevOb, CurrOb: ListGameObject;
  821.     begin
  822.         BrickWidth := CIcons[500]^^.IconPmap.Bounds.right;
  823.         BrickHeight := CIcons[500]^^.IconPmap.Bounds.bottom;
  824.         CurrLeft := XStart;
  825.         CurrOb := StartOb;
  826.         if StartOb <> nil then
  827.             PrevOb := StartOb
  828.         else
  829.             PrevOb := nil;
  830.         for i := 1 to NumBricks do
  831.             begin
  832.                 if CurrOb <> nil then
  833.                     begin
  834.                         new(CurrOb^.next);
  835.                         CurrOb := CurrOb^.next;
  836.                     end
  837.                 else
  838.                     new(CurrOb);
  839.                 CoordAndSize(TempPlace, CurrLeft, YStart, BrickWidth, BrickHeight);
  840.                 if PrevOb <> nil then
  841.                     begin
  842.                         if (abs(random) mod 1000) < score then
  843.                             InitOb(CurrOb, BRICK, BRICKII, 501, TempPlace, TempPlace, nil, PrevOb, 2, 0, 0, 0, 0, 0, 0, 0)
  844.                         else
  845.                             InitOb(CurrOb, BRICK, BRICK, 500, TempPlace, TempPlace, nil, PrevOb, 1, 0, 0, 0, 0, 0, 0, 0);
  846.                         PrevOb^.next := CurrOb;
  847.                     end
  848.                 else
  849.                     begin
  850.                         if (abs(random) mod 1000) < score then
  851.                             InitOb(CurrOb, BRICK, BRICKII, 501, TempPlace, TempPlace, nil, nil, 2, 0, 0, 0, 0, 0, 0, 0)
  852.                         else
  853.                             InitOb(CurrOb, BRICK, BRICK, 500, TempPlace, TempPlace, nil, nil, 1, 0, 0, 0, 0, 0, 0, 0);
  854.                     end;
  855.                 AddToNonMovingGrid(CurrOb);
  856.                 CurrLeft := CurrLeft + BrickWidth;
  857.                 PrevOb := CurrOb;
  858.             end;
  859.         StartOb := CurrOb;
  860.     end;        {create a row of bricks, add each to the grid}
  861. {note that you get more grey bricks the higher your score goes}
  862.  
  863.     procedure InitNonMovingGrid;
  864.         var
  865.             i, j, k: integer;
  866.     begin
  867.         for i := 1 to 10 do
  868.             for j := 1 to 10 do
  869.                 for k := 1 to 5 do
  870.                     NonMovingGrid[i, j, k] := nil;
  871.     end;        {just clear all of the non moving grid}
  872.  
  873.     procedure InitLevel;
  874.         var
  875.             i: integer;
  876.             BlankRect: Rect;
  877.     begin
  878.         InitNonMovingGrid;
  879.         new(FirstMovingObject);
  880.         InitOb(FirstMovingObject, 0, 0, 0, BlankRect, BlankRect, nil, nil, 0, 0, 0, 0, 0, 0, 0, 0); {dummy}
  881.         PaddleAndBall(FirstMovingObject);
  882.         FirstNonMovingObject := nil;
  883.         new(FirstNonMovingObject);
  884.         InitOb(FirstNonMovingObject, 0, 0, 0, BlankRect, BlankRect, nil, nil, 0, 0, 0, 0, 0, 0, 0, 0); {dummy}
  885.         i := CurrentNonMoving;
  886.         FlushLevelGraphics(128);
  887.         for i := 1 to 7 do
  888.             BrickRow(FirstNonMovingObject, 10, 30 + (i * (CIcons[500]^^.IconPmap.Bounds.bottom)), 15);
  889.         CurrentNonMoving := i;
  890.     end;        {make the brick rows, as well as the dummy objects and the paddle and the ball}
  891.  
  892.     procedure InitGame;
  893.         var
  894.             FirstNonMovingObject, FirstMovingObject: ListGameObject;
  895.     begin
  896. {KillEveryBody;}
  897. {see highest note}
  898.         if false then
  899.             begin
  900.                 rewrite(TopScore, 'HighScore');
  901.                 TopScore^ := 10;
  902.                 put(TopScore);
  903.                 close(TopScore);
  904.             end;        {you can uncomment this to set the high score to ten points}
  905.         reset(TopScore, 'HighScore');
  906.         top := TopScore^;
  907.         close(TopScore);
  908. {lives = 3; starting items; etc; you know, fun stuff}
  909.         FirstNonMovingObject := nil;
  910.         FirstMovingObject := nil;
  911.         Lives := 3;
  912.         Score := 0;
  913.         DeathCountdown := 0;
  914.         Missiles := 10;
  915.         CoolnessCounter := 0;
  916.         DontSuck := FALSE;
  917.         GameLoop(FirstNonMovingObject, FirstMovingObject);
  918.     end;
  919. end.